home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Browsers, Managers & Extensions / Mozilla Weave 0.2.7 / latest-weave.xpi / modules / engines / cookies.js < prev    next >
Text File  |  2008-10-16  |  13KB  |  336 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Bookmarks Sync.
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla.
  17.  * Portions created by the Initial Developer are Copyright (C) 2008
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *  Jono DiCarlo <jdicarlo@mozilla.org>
  22.  *
  23.  * Alternatively, the contents of this file may be used under the terms of
  24.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  25.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26.  * in which case the provisions of the GPL or the LGPL are applicable instead
  27.  * of those above. If you wish to allow use of your version of this file only
  28.  * under the terms of either the GPL or the LGPL, and not to allow others to
  29.  * use your version of this file under the terms of the MPL, indicate your
  30.  * decision by deleting the provisions above and replace them with the notice
  31.  * and other provisions required by the GPL or the LGPL. If you do not delete
  32.  * the provisions above, a recipient may use your version of this file under
  33.  * the terms of any one of the MPL, the GPL or the LGPL.
  34.  *
  35.  * ***** END LICENSE BLOCK ***** */
  36.  
  37. const EXPORTED_SYMBOLS = ['CookieEngine', 'CookieTracker', 'CookieStore'];
  38.  
  39. const Cc = Components.classes;
  40. const Ci = Components.interfaces;
  41. const Cu = Components.utils;
  42.  
  43. Cu.import("resource://weave/log4moz.js");
  44. Cu.import("resource://weave/async.js");
  45. Cu.import("resource://weave/engines.js");
  46. Cu.import("resource://weave/syncCores.js");
  47. Cu.import("resource://weave/stores.js");
  48. Cu.import("resource://weave/trackers.js");
  49.  
  50. Function.prototype.async = Async.sugar;
  51.  
  52. function CookieEngine(pbeId) {
  53.   this._init(pbeId);
  54. }
  55. CookieEngine.prototype = {
  56.   __proto__: new SyncEngine(),
  57.  
  58.   get name() { return "cookies"; },
  59.   get displayName() { return "Cookies"; },
  60.   get logName() { return "CookieEngine"; },
  61.   get serverPrefix() { return "user-data/cookies/"; },
  62.  
  63.   __store: null,
  64.   get _store() {
  65.     if (!this.__store)
  66.       this.__store = new CookieStore();
  67.     return this.__store;
  68.   },
  69.  
  70.   __core: null,
  71.   get _core() {
  72.     if (!this.__core)
  73.       this.__core = new CookieSyncCore(this._store);
  74.     return this.__core;
  75.   },
  76.  
  77.   __tracker: null,
  78.   get _tracker() {
  79.     if (!this.__tracker)
  80.       this.__tracker = new CookieTracker();
  81.     return this.__tracker;
  82.   }
  83. };
  84.  
  85. function CookieSyncCore(store) {
  86.   this._store = store;
  87.   this._init();
  88. }
  89. CookieSyncCore.prototype = {
  90.   _logName: "CookieSync",
  91.   _store: null,
  92.  
  93.   _commandLike: function CSC_commandLike(a, b) {
  94.     /* Method required to be overridden.
  95.        a and b each have a .data and a .GUID
  96.        If this function returns true, an editCommand will be
  97.        generated to try to resolve the thing.
  98.        but are a and b objects of the type in the Store or
  99.        are they "commands"?? */
  100.     return false;
  101.   }
  102. };
  103. CookieSyncCore.prototype.__proto__ = new SyncCore();
  104.  
  105. function CookieStore( cookieManagerStub ) {
  106.   /* If no argument is passed in, this store will query/write to the real
  107.      Mozilla cookie manager component.  This is the normal way to use this
  108.      class in production code.  But for unit-testing purposes, you can pass
  109.      in a stub object that will be used in place of the cookieManager. */
  110.   this._init();
  111.   this._cookieManagerStub = cookieManagerStub;
  112. }
  113. CookieStore.prototype = {
  114.   _logName: "CookieStore",
  115.   _lookup: null,
  116.  
  117.   // Documentation of the nsICookie interface says:
  118.   // name     ACString     The name of the cookie. Read only.
  119.   // value     ACString     The cookie value. Read only.
  120.   // isDomain     boolean     True if the cookie is a domain cookie, false otherwise. Read only.
  121.   // host     AUTF8String     The host (possibly fully qualified) of the cookie. Read only.
  122.   // path     AUTF8String     The path pertaining to the cookie. Read only.
  123.   // isSecure     boolean     True if the cookie was transmitted over ssl, false otherwise. Read only.
  124.   // expires     PRUint64     Expiration time (local timezone) expressed as number of seconds since Jan 1, 1970. Read only.
  125.   // status     nsCookieStatus     Holds the P3P status of cookie. Read only.
  126.   // policy     nsCookiePolicy     Holds the site's compact policy value. Read only.
  127.   // nsICookie2 deprecates expires, status, and policy, and adds:
  128.   //rawHost     AUTF8String     The host (possibly fully qualified) of the cookie without a leading dot to represent if it is a domain cookie. Read only.
  129.   //isSession     boolean     True if the cookie is a session cookie. Read only.
  130.   //expiry     PRInt64     the actual expiry time of the cookie (where 0 does not represent a session cookie). Read only.
  131.   //isHttpOnly     boolean     True if the cookie is an http only cookie. Read only.
  132.  
  133.   __cookieManager: null,
  134.   get _cookieManager() {
  135.     if ( this._cookieManagerStub != undefined ) {
  136.       return this._cookieManagerStub;
  137.     }
  138.     // otherwise, use the real one
  139.     if (!this.__cookieManager)
  140.       this.__cookieManager = Cc["@mozilla.org/cookiemanager;1"].
  141.                              getService(Ci.nsICookieManager2);
  142.     // need the 2nd revision of the ICookieManager interface
  143.     // because it supports add() and the 1st one doesn't.
  144.     return this.__cookieManager;
  145.   },
  146.  
  147.   _createCommand: function CookieStore__createCommand(command) {
  148.     /* we got a command to create a cookie in the local browser
  149.        in order to sync with the server. */
  150.  
  151.     this._log.debug("CookieStore got create command for: " + command.GUID);
  152.  
  153.     // this assumes command.data fits the nsICookie2 interface
  154.     if ( !command.data.isSession ) {
  155.       // Add only persistent cookies ( not session cookies )
  156.       this._cookieManager.add( command.data.host,
  157.                    command.data.path,
  158.                    command.data.name,
  159.                    command.data.value,
  160.                    command.data.isSecure,
  161.                    command.data.isHttpOnly,
  162.                    command.data.isSession,
  163.                    command.data.expiry );
  164.     }
  165.   },
  166.  
  167.   _removeCommand: function CookieStore__removeCommand(command) {
  168.     /* we got a command to remove a cookie from the local browser
  169.        in order to sync with the server.
  170.        command.data appears to be equivalent to what wrap() puts in
  171.        the JSON dictionary. */
  172.  
  173.     if (!(command.GUID in this._lookup)) {
  174.       this._log.warn("Warning! Remove command for unknown item: " + command.GUID);
  175.       return;
  176.     }
  177.  
  178.     this._log.debug("CookieStore got remove command for: " + command.GUID);
  179.  
  180.     /* I think it goes like this, according to
  181.      http://developer.mozilla.org/en/docs/nsICookieManager
  182.      the last argument is "always block cookies from this domain?"
  183.      and the answer is "no". */
  184.     this._cookieManager.remove(this._lookup[command.GUID].host,
  185.                                this._lookup[command.GUID].name,
  186.                                this._lookup[command.GUID].path,
  187.                                false);
  188.   },
  189.  
  190.   _editCommand: function CookieStore__editCommand(command) {
  191.     /* we got a command to change a cookie in the local browser
  192.        in order to sync with the server. */
  193.  
  194.     if (!(command.GUID in this._lookup)) {
  195.       this._log.warn("Warning! Edit command for unknown item: " + command.GUID);
  196.       return;
  197.     }
  198.  
  199.     this._log.debug("CookieStore got edit command for: " + command.GUID);
  200.  
  201.     /* Look up the cookie that matches the one in the command: */
  202.     var iter = this._cookieManager.enumerator;
  203.     var matchingCookie = null;
  204.     while (iter.hasMoreElements()){
  205.       let cookie = iter.getNext();
  206.       if (cookie.QueryInterface( Ci.nsICookie2 ) ){
  207.         // see if host:path:name of cookie matches GUID given in command
  208.     let key = cookie.host + ":" + cookie.path + ":" + cookie.name;
  209.     if (key == command.GUID) {
  210.       matchingCookie = cookie;
  211.       break;
  212.     }
  213.       }
  214.     }
  215.     // Update values in the cookie:
  216.     for (var key in command.data) {
  217.       // Whatever values command.data has, use them
  218.       matchingCookie[ key ] = command.data[ key ];
  219.     }
  220.     // Remove the old incorrect cookie from the manager:
  221.     this._cookieManager.remove( matchingCookie.host,
  222.                 matchingCookie.name,
  223.                 matchingCookie.path,
  224.                 false );
  225.  
  226.     // Re-add the new updated cookie:
  227.     if ( !command.data.isSession ) {
  228.       /* ignore single-session cookies, add only persistent cookies.  */
  229.       this._cookieManager.add( matchingCookie.host,
  230.                    matchingCookie.path,
  231.                    matchingCookie.name,
  232.                    matchingCookie.value,
  233.                    matchingCookie.isSecure,
  234.                    matchingCookie.isHttpOnly,
  235.                    matchingCookie.isSession,
  236.                    matchingCookie.expiry );
  237.     }
  238.  
  239.     // Also, there's an exception raised because
  240.     // this._data[comand.GUID] is undefined
  241.   },
  242.  
  243.   wrap: function CookieStore_wrap() {
  244.     /* Return contents of this store, as JSON.
  245.        A dictionary of cookies where the keys are GUIDs and the
  246.        values are sub-dictionaries containing all cookie fields. */
  247.     let items = {};
  248.     var iter = this._cookieManager.enumerator;
  249.     while (iter.hasMoreElements()) {
  250.       var cookie = iter.getNext();
  251.       if (cookie.QueryInterface( Ci.nsICookie2 )) {
  252.           // String used to identify cookies is
  253.           // host:path:name
  254.           if ( cookie.isSession ) {
  255.             /* Skip session-only cookies, sync only persistent cookies. */
  256.             continue;
  257.           }
  258.  
  259.           let key = cookie.host + ":" + cookie.path + ":" + cookie.name;
  260.           items[ key ] = { parentGUID: '',
  261.                                 name: cookie.name,
  262.                                 value: cookie.value,
  263.                                 isDomain: cookie.isDomain,
  264.                                 host: cookie.host,
  265.                                 path: cookie.path,
  266.                                 isSecure: cookie.isSecure,
  267.                                 // nsICookie2 values:
  268.                                 rawHost: cookie.rawHost,
  269.                                 isSession: cookie.isSession,
  270.                                 expiry: cookie.expiry,
  271.                                 isHttpOnly: cookie.isHttpOnly };
  272.  
  273.           /* See http://developer.mozilla.org/en/docs/nsICookie
  274.              Note: not syncing "expires", "status", or "policy"
  275.              since they're deprecated. */
  276.  
  277.       }
  278.     }
  279.     this._lookup = items;
  280.     return items;
  281.   },
  282.  
  283.   wipe: function CookieStore_wipe() {
  284.     /* Remove everything from the store.  Return nothing.
  285.        TODO are the semantics of this just wiping out an internal
  286.        buffer, or am I supposed to wipe out all cookies from
  287.        the browser itself for reals? */
  288.     this._cookieManager.removeAll();
  289.   },
  290.  
  291.   _resetGUIDs: function CookieStore__resetGUIDs() {
  292.     let self = yield;
  293.     /* called in the case where remote/local sync GUIDs do not
  294.        match.  We do need to override this, but since we're deriving
  295.        GUIDs from the cookie data itself and not generating them,
  296.        there's basically no way they can get "out of sync" so there's
  297.        nothing to do here. */
  298.   }
  299. };
  300. CookieStore.prototype.__proto__ = new Store();
  301.  
  302. function CookieTracker() {
  303.   this._init();
  304. }
  305. CookieTracker.prototype = {
  306.   _logName: "CookieTracker",
  307.  
  308.   _init: function CT__init() {
  309.     this._log = Log4Moz.Service.getLogger("Service." + this._logName);
  310.     this._score = 0;
  311.     /* cookieService can't register observers, but what we CAN do is
  312.        register a general observer with the global observerService
  313.        to watch for the 'cookie-changed' message. */
  314.     let observerService = Cc["@mozilla.org/observer-service;1"].
  315.                           getService(Ci.nsIObserverService);
  316.     observerService.addObserver( this, 'cookie-changed', false );
  317.   },
  318.  
  319.   // implement observe method to satisfy nsIObserver interface
  320.   observe: function ( aSubject, aTopic, aData ) {
  321.     /* This gets called when any cookie is added, changed, or removed.
  322.        aData will contain a string "added", "changed", etc. to tell us which,
  323.        but for now we can treat them all the same. aSubject is the new
  324.        cookie object itself. */
  325.     var newCookie = aSubject.QueryInterface( Ci.nsICookie2 );
  326.     if ( newCookie ) {
  327.       if ( !newCookie.isSession ) {
  328.     /* Any modification to a persistent cookie is worth
  329.        10 points out of 100.  Ignore session cookies. */
  330.     this._score += 10;
  331.       }
  332.     }
  333.   }
  334. }
  335. CookieTracker.prototype.__proto__ = new Tracker();
  336.